home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
asmutil
/
80x0393.zip
/
ANTIDBG.TXT
< prev
next >
Wrap
Text File
|
1993-03-30
|
17KB
|
425 lines
Anti Debugging Tricks
By:
Inbar Raz
Assistance by Eden Shochat and Yossi Gottlieb
Release number 5
Today's anti debugging tricks devide into two categories:
1. Preventive actions;
2. Self-modifying code.
Most debugging tricks, as for today, are used within viruses, in order to
avoid dis-assembly of the virus, as it will be exampled later in this file.
Another large portion of anti debugging tricks is found with software
protection programs, that use them in order to make the cracking of the
protection harder.
1. Preventive actions:
----------------------
Preventive actions are, basically, actions that the program takes in order
to make the user unable to dis-assemble the code or trace it while running.
1.1. Interrupt disable:
Interrupt disable is probably the most common form of anti-debugging
tricks. It can be done in several ways:
1.1.1. Hardware masking of interrupt:
In order to avoid tracing of a code, one usually disables the
interrupt via the 8259 Interrupt Controller, addressed by read/write
actions to port 21h. The 8259 Interrupt Controller controls the IRQ
lines. This means that any IRQ between 0 and 7 may be disabled by
this action. Bit 0 is IRQ0, bit 1 is IRQ1 etc. Since IRQ1 is the
keyboard interrupt, you may disable the keyboard without the
debugger being able to bypass it.
Example:
CS:0100 E421 IN AL,21
CS:0102 0C02 OR AL,02
CS:0104 E621 OUT 21,AL
Just as a side notice, the keyboard may be also disabled by
commanding the Programmable Peripheral Interface (PPI), port 61h.
Example:
CS:0100 E461 IN AL,61
CS:0102 0C80 OR AL,80
CS:0104 E661 OUT 61,AL
1.1.2. Software masking of interrupt:
This is quite an easy form of an anti-debugging trick. All you
have to do is simply replace the vectors of interrupts debuggers
use, or any other interrupt you will not be using or expecting to
occur. Do not forget to restore the original vectors when you are
finished. It is adviseable to use manual change of vector, as shown
below, rather than to change it using interrupt 21h service 25h,
because any debugger that has gained control of interrupt 21h may
replace your vector with the debugger's. The example shows an
interception of interrupt 03h - the breakpoint interrupt.
Example:
CS:0100 EB04 JMP 0106
CS:0102 0000 ADD [BX+SI],AL
CS:0104 0000 ADD [BX+SI],AL
CS:0106 31C0 XOR AX,AX
CS:0108 8EC0 MOV ES,AX
CS:010A 268B1E0C00 MOV BX,ES:[000C]
CS:010F 891E0201 MOV [0102],BX
CS:0113 268B1E0E00 MOV BX,ES:[000E]
CS:0118 891E0401 MOV [0104],BX
CS:011C 26C7064C000000 MOV Word Ptr ES:[000C],0000
CS:0123 26C7064E000000 MOV Word Ptr ES:[000E],0000
1.1.3. Vector manipulation
This method involves manipulations of the interrupt vectors,
mainly for proper activation of the algorithm. Such action, as
exampled, may be used to decrypt a code (see also 2.1), using data
stored ON the vectors. Ofcourse, during normal operation of the
program, vectors 01h and 03h are not used, so unless you are trying
to debug such a program, it works fine.
Example:
CS:0100 31C0 XOR AX,AX
CS:0102 8ED0 MOV SS,AX
CS:0104 BC0E00 MOV SP,000E
CS:0107 2E8B0E3412 MOV CX,CS:[1234]
CS:010C 50 PUSH AX
CS:010D 31C8 XOR AX,CX
CS:010F 21C5 AND BP,AX
CS:0111 58 POP AX
CS:0112 E2F8 LOOP 010C
1.1.4. Interrupt replacement
This is a really nasty trick, and it should be used ONLY if you
are ABSOLUTELY sure that your programs needs no more debugging. What
you should do is copy the vectors of some interrupts you will be
using, say 16h and 21h, onto the vectors of interrupt 01h and 03h,
that do not occur during normal operation of the program. If the
user wants to debug the program, he would have to search for every
occurance of INT 01, and replace it with the appropriate INT
instruction. This trick is very effective if used together with the
fact that the INT 3 intruction has a ONE BYTE opcode - 0CCh, which
can not be changed to any other interrupt.
Example:
CS:0100 FA CLI
CS:0101 31C0 XOR AX,AX
CS:0103 8EC0 MOV ES,AX
CS:0105 26A18400 MOV AX,ES:[0084]
CS:0109 26A30400 MOV ES:[0004],AX
CS:010D 26A18600 MOV AX,ES:[0086]
CS:0111 26A30600 MOV ES:[0006],AX
CS:0115 B44C MOV AH,4C
CS:0117 CD01 INT 01
1.2. Time watch:
This may be a less common method, but it is usefull against debuggers
that disable all interrupts except for the time that the program is
executed, such as Borland's Turbo Debugger. This method simply retains
the value of the clock counter, updated by interrupt 08h, and waits in an
infinite loop until the value changes. Another example is when you mask
the timer interrupt by ORing the value INed from port 21h with 01h and
then OUTing it back, thus disabling the IRQ0 - Timer interrupt. Note that
this method is usefull only against RUN actions, not TRACE/PROCEED ones.
Example:
CS:0100 2BC0 SUB AX,AX
CS:0102 FB STI
CS:0103 8ED8 MOV DS,AX
CS:0105 8A266C04 MOV AH,[046C]
CS:0109 A06C04 MOV AL,[046C]
CS:010C 3AC4 CMP AL,AH
CS:010E 74F9 JZ 0109
1.3. Fool the debugger:
This is a very nice technique, that works especially and only on those
who use Turbo Debugger or its kind. What you should do is init a jump to
a middle of an instruction, whereas the real address actually contains
another opcode. If you work with a normal step debugger such as Debug or
SymDeb, it won't work since the debugger jumps to the exact address of
the jump, and not to the beginning of an instruction at the closest
address, like Turbo Debugger.
Example:
CS:0100 E421 IN AL,21
CS:0102 B0FF MOV AL,FF
CS:0104 EB02 JMP 0108
CS:0106 C606E62100 MOV Byte Ptr [21E6],00
CS:010B CD20 INT 20
Watch this:
CS:0108 E621 OUT 21,AL
Notice:
This trick does NOT effect the run of the program in ANY debugger. Its
only use is to try to deceive the user into thinking another opcode is
used, while another is actually run.
1.4. Check CPU Flags:
This is a nice trick, effective against almost any real mode debugger.
What you should do is simply set the trace flag off somewhere in your
program, and check for it later. If it was turned on, a debugger runs in
the background...
Example:
CS:0100 9C PUSHF
CS:0101 58 POP AX
CS:0102 25FFFE AND AX,FEFF
CS:0105 50 PUSH AX
CS:0106 9D POPF
In the middle of the program:
CS:1523 9C PUSHF
CS:1524 58